# float32二进制与十进制转换
import numpy as np


def dec2bin(num):
    if num > 3.4028234663852886e+38 or num < -3.4028234663852886e+38:
        return ''
    if num < 0:
        sign = '1'
        num = 0 - num
    else:
        sign = '0'
    int_part = int(num)
    float_part = num - int_part
    if int_part > 0:
        int_part_str = ''
        float_part_str = ''
        while int_part != 0:
            int_part_str = str(int_part % 2) + int_part_str
            int_part = int_part // 2
        while float_part != 1.0 and len(float_part_str) + len(int_part_str) < 24:
            float_part *= 2
            if float_part >= 1.0:
                float_part -= 1.0
                float_part_str = float_part_str + '1'
            else:
                float_part_str = float_part_str + '0'
        epow = len(int_part_str) + 126
        tail = int_part_str[1:] + float_part_str
        while len(tail) < 23:
            tail = tail + '0'
        if len(tail) > 23:
            tail = tail[:23]
        epow_str = bin(epow)[2:]
        while len(epow_str) < 8:
            epow_str = '0' + epow_str
        res = sign + epow_str + tail
        return res
    else:
        float_part_str = ''
        valid_bit = 0
        zero_bit = 0
        flag = False
        while float_part != 1.0 and valid_bit < 24:
            float_part *= 2
            if float_part >= 1.0:
                float_part -= 1.0
                float_part_str = float_part_str + '1'
                if not flag:
                    flag = True
            else:
                float_part_str = float_part_str + '0'
            if flag:
                valid_bit += 1
            else:
                zero_bit += 1
        epow = 126 - zero_bit
        epow_str = bin(epow)[2:]
        while len(epow_str) < 8:
            epow_str = '0' + epow_str
        tail = float_part_str[zero_bit + 1:]
        while len(tail) < 23:
            tail = tail + '0'
        res = sign + epow_str + tail
        return res


def bin2dec(num):
    if len(num) != 32:
        return ''
    if num[0] == '1':
        sign = -1.0
    else:
        sign = 1.0
    epow_str = num[1:9]
    tail = num[9:]
    epow = 0
    for i in range(8):
        epow += pow(2, i) * int(epow_str[7 - i])
    epow -= 127
    epow = pow(2.0, epow)
    tail_float = 1
    for i in range(23):
        tail_float += int(tail[i]) * pow(2, -i-1)
    res = sign * tail_float * epow
    return res


def dec2bin16(num):
    if num > 65504 or num < -65504 or -pow(2, -14) < num < pow(2, -14):
        return ''
    if num < 0:
        sign = '1'
        num = 0 - num
    else:
        sign = '0'
    int_part = int(num)
    float_part = num - int_part
    if int_part > 0:
        int_part_str = ''
        float_part_str = ''
        while int_part != 0:
            int_part_str = str(int_part % 2) + int_part_str
            int_part = int_part // 2
        while float_part != 1.0 and len(float_part_str) + len(int_part_str) < 11:
            float_part *= 2
            if float_part >= 1.0:
                float_part -= 1.0
                float_part_str = float_part_str + '1'
            else:
                float_part_str = float_part_str + '0'
        epow = len(int_part_str) + 14
        tail = int_part_str[1:] + float_part_str
        while len(tail) < 10:
            tail = tail + '0'
        if len(tail) > 10:
            tail = tail[:10]
        epow_str = bin(epow)[2:]
        while len(epow_str) < 5:
            epow_str = '0' + epow_str
        res = sign + epow_str + tail
        return res
    else:
        float_part_str = ''
        valid_bit = 0
        zero_bit = 0
        flag = False
        while float_part != 1.0 and valid_bit < 11:
            float_part *= 2
            if float_part >= 1.0:
                float_part -= 1.0
                float_part_str = float_part_str + '1'
                if not flag:
                    flag = True
            else:
                float_part_str = float_part_str + '0'
            if flag:
                valid_bit += 1
            else:
                zero_bit += 1
        epow = 14 - zero_bit
        epow_str = bin(epow)[2:]
        while len(epow_str) < 5:
            epow_str = '0' + epow_str
        tail = float_part_str[zero_bit + 1:]
        while len(tail) < 10:
            tail = tail + '0'
        res = sign + epow_str + tail
        return res


def bin2dec16(num):
    if len(num) != 16:
        return ''
    if num[0] == '1':
        sign = -1.0
    else:
        sign = 1.0
    epow_str = num[1:6]
    tail = num[6:]
    epow = 0
    for i in range(5):
        epow += pow(2, i) * int(epow_str[4 - i])
    epow -= 15
    epow = pow(2.0, epow)
    tail_float = 1
    for i in range(10):
        tail_float += int(tail[i]) * pow(2, -i-1)
    res = sign * tail_float * epow
    return res


# def str2tensor(raw):
#     raw_shape = raw.shape
#     lst = []
#     for x in raw.flatten():
#         lst.append(bin2dec(x))
#     res = np.asarray(lst, dtype=np.float32)
#     res = res.reshape(raw_shape)
#     return res


def in_range_float16(num):
    return pow(2, -14) <= num <= 65504 or -65504 <= num <= -pow(2, -14)


# if __name__ == '__main__':
    # f = bin2dec('11111111011111111101000001100110')
    # f = f - 1.6
    # print(f)
    # print(dec2bin(-3.4013783447010284e+38))
    # f = -7.049954509064094e-10
    # print(dec2bin16(f))
